package com.softwareengineering.trafficapplicationv2;

/**
 * This file is part of the Traffic Simulation Application.
 * The Traffic Simulation Application is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * The Traffic Simulation Application is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with the Traffic Simulation Application.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @file LaneChange.java
 * @author (c) Martin Treiber, http://traffic-simulation.de/
 * @alterations David Black, Chris Nelson, and Garrett Stibbs, (c) December 03, 2012
 * @description Implementation of the lane-changing model
 * 				MOBIL ("Minimizing Overall Brakings Induced by Lane-changes"),
 * 				see "http://141.30.51.183/~treiber/publications/MOBIL.pdf"
 * 				M. Treiber and D. Helbing, Realistische Mikrosimulation von
 * 				Strassenverkehr mit einem einfachen Modell, 16. Symposium
 * 				"Simulationstechnik ASIM 2002" Rostock, 10.09 -13.09.2002,
 * 				edited by Djamshid Tavangarian and Rolf Gr\"utzner pp. 514--520.
 * @note 	only decision logic to change lanes
 * 			actual process of lane changing: MicrosStreet
 * 			coding lanechanging duration: Constants.T_DELAY => realLane defined in Car.java
 * 
 */

public class LaneChange implements Constants {

	private double biasRight = 0;
	private double bsave=MAIN_BSAVE;     // maximum safe braking deceleration for other vehicles
	private double bsaveSelf=MAIN_BSAVE_SELF;     // maximum safe braking deceleration for subject vehicle
	private double db=DB_CAR;      // changing threshold
	private double gapMin=MAIN_SMIN;       // minimum safe (net) distance
	private double p=P_FACTOR_CAR; // politeness factor
	final int LEFT=0;
	final int RIGHT=1;             

	public LaneChange (double p, double db){
		assert bsaveSelf <= MAX_BRAKING;
		this.p=p;
		this.db=db;
	}

	public LaneChange (double p, double db, 
			double gapMin, double bsave, double biasRight){
		this(p, db);
		assert bsave <= MAX_BRAKING;
		this.gapMin=gapMin;
		this.bsave=bsave;
		this.biasRight=biasRight;
	}

	public LaneChange (String lctype){
		if( lctype.equals("truck")){
			p=P_FACTOR_TRUCK;
			db=DB_TRUCK;
			gapMin=MAIN_SMIN;
			bsave=MAIN_BSAVE;
			biasRight=BIAS_RIGHT_TRUCK;
		}
	}

	public boolean changeOK(Moveable me, Moveable fOld, 
			Moveable fNew, Moveable bNew) {

		double gapFront=fNew.position() - me.position() - me.length();
		if (gapFront <= gapMin) return false;
		
		double gapBack=me.position() - bNew.position() - bNew.length();
		if (gapBack <= gapMin) return false;

		// safety criterion (a > -bsave) 
		double bNew_acc = bNew.model().calcAcc(bNew,me);
		if (bNew_acc < -bsave) return false;
		
		double my_acc = me.model().calcAcc(me,fNew);
		if (my_acc < -bsaveSelf) return false;

		// incentive criterion (always model of BACK vehicle used!!)
		// works also for on-ramp: on-ramp has 1 lane with index 0
		// === LEFT on main road -> strong desired to change = 
		// large positive biasRight for lcModel of ramp vehicles

		double my_adv  = my_acc - me.model().calcAcc(me,fOld)
				+ ((me.lane()==LEFT) ? 1 : -1) * biasRight;

		double others_disadv = bNew.model().calcAcc(bNew,fNew) - bNew_acc;

		if (others_disadv<0) others_disadv=0;
		
		return my_adv - p*others_disadv > db ? true : false;
	}
	
	public double get_db(){return(db);}
	
	public double get_p(){return(p);}
	
	public void set_biasRight(double bias){this.biasRight=bias;
	}
	
	public void set_bsave(double bsave){
		assert bsave <= MAX_BRAKING;
		this.bsave=bsave;
	}

	public void set_db(double db){this.db=db;}

	public void set_gapMin(double gapMin){this.gapMin=gapMin;}

	public void set_p(double p){this.p=p;}
	
}
